#include<stdio.h>
#include<stdlib.h>

void init(){
	lexer_line = 1;
	lexer_col = 0;
		
	ADD_WORD("if",T_IF);
	ADD_WORD("else",T_ELSE);
	ADD_WORD("while",T_WHILE);
	ADD_WORD("for",T_FOR);
	
	ADD_WORD("public",T_PUBLIC);
	ADD_WORD("private",T_PRIVATE);
	ADD_WORD("class",T_CLASS);
	ADD_WORD("implements",T_IMPLEMENTS);
	ADD_WORD("extends",T_EXTENDS);
	ADD_WORD("static",T_STATIC);
	
	ADD_WORD("main",T_MAIN);
	
	ADD_WORD("int",T_INT);
	ADD_WORD("void",T_VOID);
	ADD_WORD("float",T_FLOAT);
	ADD_WORD("String",T_STRING);
	
	ADD_WORD("C_stdio",T_C_IO_CALL);
}

int getch(){
	x = getc(stdin);
	old_lexer_line = lexer_line;
	old_lexer_col = lexer_col;
	lexer_line = lexer_line + (x == '\n');
	lexer_col = lexer_col*(x != '\n') + 1;
	return (x != EOF);
}

void ungetch(){
	lexer_line = old_lexer_line;
	lexer_col = old_lexer_col;
	ungetc(x,stdin);
}

int is_space(){
	return ((x==' ')+(x=='\r')+(x=='\t')+(x=='\n'));
}

int is_letter(){
	return ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z'));
}

int is_digit(){
	return (x >= '0' && x <= '9');
}

int is_eof(){
	return (x=='$');
}

int getToken(){
	int state,i,k,ok,is_comm;
	getch();
	while(is_space()) getch();
	if(is_eof()) return T_EOF;
	buffer[0]='\0';
	switch(x){
		case '!':
			return T_NOT;
		case '<':
			getch();
			if(x == '=') return T_LS_EQ;
			ungetch();
			return T_LS;
		case '>':
			getch();
			if(x == '=') return T_GT_EQ;
			ungetch();
			return T_GT;
		case '&':
			getch();
			if(x == '&') return T_AND_BOOL;
			ungetch();
			return T_AND_BIT;
		case '|':
			getch();
			if(x == '|') return T_OR_BIT;
			ungetch();
			return T_OR_BOOL;			
		case '+':
			getch();
			if(x == '+') return T_INC;
			ungetch();
			return T_PLUS;
		case '-':
			getch();
			if(x == '-') return T_DEC;
			ungetch();
			return T_MINUS;
		case '=':
			getch();
			if(x == '=') return T_IS_EQUAL_BOOL;
			ungetch();
			return T_ATTR;
		case '*':
			return T_TIMES;
		case '/':
			getch();
			if(x == '*'){ // TODO: fim inesperado
				is_comm = 1;
				do{
					getch();
					if(x == '*'){
						getch();
						is_comm = (x != '/');
					}else if(x == '$'){
						ERROR_MSG("Fim inesperado");
						return T_ERROR;
					}
				} while(is_comm);
				return getToken();
			} else if(x == '/'){
				is_comm = 1;
				do{
					getch();
					is_comm = (x != '\n');
				} while(is_comm);
				return getToken();
			}else{
				ungetch();
				return T_DIV;
			}
		case '[':
			return T_OP_BRACKET;
		case ']':
			return T_CL_BRACKET;
		case '{':
			return T_OP_BRACE;
		case '}':
			return T_CL_BRACE;
		case '(':
			return T_OP_PAR;
		case ')':
			return T_CL_PAR;
		case ';':
			return T_COLON;
		case ',':
			return T_COMMA;
		case '.':
			return T_DOT;
		default:
			state = T_ERROR;
			i = 0;			
			if(is_digit()){
				state = T_INT_NUMBER;
				while(1){
					buffer[i++] = x;
					getch();
					if(x == '.') state = T_FLOAT_NUMBER;
					else if(!is_digit()) break;
				}
				buffer[i]='\0';
				ungetch();
				return state;
			}
			//
			memset(word_next,0,sizeof word_next);
			while(is_letter()){
				ok=0;
				for(k=0;k<NUM_WORDS;k++){
					if((i==word_next[k])&&(i<word_len[k])&&(x==word[k][i])){
						if((word_len[k]-1)==i){
							state = word_token[k];
							//printf("#\n");
						}
						word_next[k]++; ok++;
					}
				}
				if(!ok) state = T_ID;
				buffer[i] = x;
				getch(); i++;
			}
			buffer[i]='\0';
			ungetch();
			return state;
	}
	
}